package com.qipay.pay.impl;

import com.qipay.baas.model.Order;
import com.qipay.order.config.OrderChannelEnum;
import com.qipay.order.config.OrderStateEnum;
import com.qipay.order.service.OrderService;
import com.qipay.pay.TradeService;
import com.qipay.pay.entity.CpTradeCloseRequest;
import com.qipay.pay.entity.CpTradeQueryRequest;
import com.qipay.scalar.type.ApiResultCodeEnum;
import com.qipay.security.jwt.JWTUser;
import com.qipay.sp.SpService;
import com.qipay.sp.excutor.ExcutorFactory;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

@Service
public class TradeServiceImpl implements TradeService {

    @Autowired
    OrderService orderService;
    @Autowired
    SpService spService;

    @Override
    public Map<String, Object> tradeQuery(CpTradeQueryRequest entity, JWTUser loggedUser) throws Exception {
        Assert.notNull(loggedUser, "找不到登录信息");
        Assert.notNull(entity, "请输入交易信息");
        Assert.notNull(entity.getMchId(), "请输入商户号");
        Assert.isTrue(StringUtils.equals(entity.getMchId(), loggedUser.getUsername())
                , "输入的商户号与登录信息不一致");
        Assert.isTrue(entity.getOutTradeNo() != null || entity.getTransactionId() != null,
                "请输入CP订单号或琦付订单号");
        Assert.notNull(entity.getNonceStr(), "请输入nonce_str");

        Order order = null;
        if (StringUtils.isNotBlank(entity.getTransactionId())) {
            order = orderService.getByCpidAndTradeNo(loggedUser.getId(), entity.getTransactionId());
        } else if (StringUtils.isNotBlank(entity.getOutTradeNo())) {
            order = orderService.getByCpidAndOutTradeNo(loggedUser.getId(), entity.getOutTradeNo());
        }

        Assert.notNull(order, "找不到相应订单信息");

        if (!Objects.equals(order.getState(), OrderStateEnum.NOTPAY.getType())
                && !Objects.equals(order.getState(), OrderStateEnum.SUCCESS.getType())) {
            Map<String, Object> result = new HashMap<>();
            result.put("result_code", 0);
            result.put("mch_id", loggedUser.getUsername());
            result.put("nonce_str", System.currentTimeMillis());
            result.put("trade_state", OrderStateEnum.getByType(order.getState()).toString());
            return result;
        }

        ExcutorFactory excutorFactory = spService.getFactory(order.getSpId());

        OrderChannelEnum orderChannel = OrderChannelEnum.getByType(order.getChannelType());
        Map<String, Object> result = null;
        switch (orderChannel) {
            case WECHAT:
                result = excutorFactory.createWxTradeQueryExcutor().excutor(order);
                break;
            case ALIPAY:
                result = excutorFactory.createAlipayTradeQueryExcutor().excutor(order);
                break;
            case WITHDRAW:
                result = excutorFactory.createWithdrawQueryExcutor().excutor(order);
                break;
            default:
                result = excutorFactory.createWxTradeQueryExcutor().excutor(order);
        }

        Assert.notNull(result, "请求第三方接口失败");

        if (result.get("result_code") != null && "0".equals(result.get("result_code").toString())) {
            if (result.get("trade_state") != null && "SUCCESS".equals(result.get("trade_state").toString())) {
                if (Objects.equals(order.getState(), OrderStateEnum.NOTPAY.getType())) {
                    String outTransactionId = result.getOrDefault("out_transaction_id", "").toString();
                    orderService.setOrderSuccess(order.getId(), outTransactionId);
                }
                result.put("total_fee", order.getAmount());
                result.put("transaction_id", order.getTradeNo());
                result.put("out_trade_no", order.getOutTradeNo());
            }
            result.remove("out_transaction_id");
        }

        return result;
    }

    @Override
    public Map<String, Object> tradeClose(CpTradeCloseRequest entity, JWTUser loggedUser) throws Exception {
        Assert.notNull(loggedUser, "找不到登录信息");
        Assert.notNull(entity, "请输入交易信息");
        Assert.notNull(entity.getMchId(), "请输入商户号");
        Assert.isTrue(StringUtils.equals(entity.getMchId(), loggedUser.getUsername())
                , "输入的商户号与登录信息不一致");
        Assert.isTrue(entity.getOutTradeNo() != null || entity.getTransactionId() != null,
                "请输入CP订单号或琦付订单号");
        Assert.notNull(entity.getNonceStr(), "请输入nonce_str");

        Order order = null;
        if (StringUtils.isNotBlank(entity.getTransactionId())) {
            order = orderService.getByCpidAndTradeNo(loggedUser.getId(), entity.getTransactionId());
        } else if (StringUtils.isNotBlank(entity.getOutTradeNo())) {
            order = orderService.getByCpidAndOutTradeNo(loggedUser.getId(), entity.getOutTradeNo());
        }

        Assert.notNull(order, "找不到相应订单信息");

        if (Objects.equals(order.getState(), OrderStateEnum.FREEZED.getType())
                || Objects.equals(order.getState(), OrderStateEnum.SUCCESS.getType())
                || Objects.equals(order.getState(), OrderStateEnum.CLOSE.getType())) {
            Map<String, Object> result = new HashMap<>();
            result.put("result_code", 1);
            result.put("mch_id", loggedUser.getUsername());
            result.put("nonce_str", System.currentTimeMillis());
            result.put("err_code", ApiResultCodeEnum.ERROR_ORDER_STATUS.getInfo());
            result.put("err_msg", "当前订单状态为" + OrderStateEnum.getByType(order.getState()).toString());
            return result;
        }

        ExcutorFactory excutorFactory = spService.getFactory(order.getSpId());

        OrderChannelEnum orderChannel = OrderChannelEnum.getByType(order.getChannelType());
        Map<String, Object> result = null;
        switch (orderChannel) {
            case WECHAT:
                result = excutorFactory.createWxTradeCloseExcutor().excutor(order);
                break;
            case ALIPAY:
                result = excutorFactory.createAlipayTradeCloseExcutor().excutor(order);
                break;
            default:
                result = excutorFactory.createWxTradeCloseExcutor().excutor(order);
        }

        Assert.notNull(result, "请求第三方接口失败");

        if (result.get("result_code") != null && "0".equals(result.get("result_code").toString())) {
            orderService.setOrderClose(order);
        }

        return result;
    }
}
